package cn.abcsys.cloud.devops.pipeline.core.impl;

import java.io.IOException;
import java.net.ConnectException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSONObject;
import com.offbytwo.jenkins.JenkinsServer;
import com.offbytwo.jenkins.model.BuildResult;
import com.offbytwo.jenkins.model.JobWithDetails;

import cn.abcsys.cloud.devops.pipeline.builder.RequestCommand;
import cn.abcsys.cloud.devops.pipeline.builder.config.JenkinsJobXmls;
import cn.abcsys.cloud.devops.pipeline.common.CiHost;
import cn.abcsys.cloud.devops.pipeline.common.Common;
import cn.abcsys.cloud.devops.pipeline.common.GitLab;
import cn.abcsys.cloud.devops.pipeline.common.JenkinsItem;
import cn.abcsys.cloud.devops.pipeline.common.Status;
import cn.abcsys.cloud.devops.pipeline.common.SystemConfig;
import cn.abcsys.cloud.devops.pipeline.core.PipelineCore;
import cn.abcsys.cloud.devops.pipeline.util.HttpClient;
import cn.abcsys.cloud.devops.pipeline.util.Result;
import cn.abcsys.cloud.devops.pipeline.util.SSH;

@Component
public class PipelineCoreImpl implements PipelineCore{
	private static final Logger LOGGER = Logger.getLogger(PipelineCoreImpl.class);
	private static JenkinsServer jenkinsServer;
	@Autowired
	private SystemConfig systemConfig;
	@Override
	public Result getGitProjects(GitLab gitLab, String private_token) {
		Result check_gitlab = checkGitLabUrl(gitLab);
		if(!check_gitlab.isSuccess()){
			return check_gitlab;
		}
		HttpClient httpClient = new HttpClient();
		String url = RequestCommand.getProjectsCommand(gitLab);
		Map<String, String> param = new HashMap<>();
		if(!StringUtils.isEmpty(private_token)){
			param.put("private_token", private_token);
		}
		String result = httpClient.get(param, url);
		Result info = checkResult(result);
		if(!StringUtils.isEmpty(result)&&info.isSuccess()){
			LOGGER.info("get projects success");
			return new Result(true,result,"get projects success");
		}
		return info;
	}

	@Override
	public Result getGitSingleProject(GitLab gitLab, String private_token) {
		Result check_gitlab = checkGitLabUrl(gitLab);
		if(!check_gitlab.isSuccess()){
			return check_gitlab;
		}
		HttpClient httpClient = new HttpClient();
		String url = RequestCommand.getSingleProjectCommand(gitLab);
		Map<String, String> param = new HashMap<>();
		if(!StringUtils.isEmpty(private_token)){
			param.put("private_token", private_token);
		}
		String result = httpClient.get(param, url);
		Result info = checkResult(result);
		if(!StringUtils.isEmpty(result)&&info.isSuccess()){
			LOGGER.info("get project success");
			return new Result(true,result,"get project success");
		}
		return info;
	}

	@Override
	public Result getGitProjectBranches(GitLab gitLab, String private_token) {
		Result check_gitlab = checkGitLabUrl(gitLab);
		if(!check_gitlab.isSuccess()){
			return check_gitlab;
		}
		HttpClient httpClient = new HttpClient();
		String url = RequestCommand.getProjectBranchsCommand(gitLab);
		Map<String, String> param = new HashMap<>();
		if(!StringUtils.isEmpty(private_token)){
			param.put("private_token", private_token);
		}
		String result = httpClient.get(param, url);
		Result info = checkResult(result);
		if(!StringUtils.isEmpty(result)&&info.isSuccess()){
			LOGGER.info("get branches success");
			return new Result(true,result,"get branches success");
		}
		return info;
	}

	@Override
	public Result getGitProjectSingleBranch(GitLab gitLab, String private_token,
			String branch_name) {
		Result check_gitlab = checkGitLabUrl(gitLab);
		if(!check_gitlab.isSuccess()){
			return check_gitlab;
		}
		HttpClient httpClient = new HttpClient();
		String url = RequestCommand.getProjectSingleBranchCommand(gitLab);
		Map<String, String> param = new HashMap<>();
		if(!StringUtils.isEmpty(private_token)){
			param.put("private_token", private_token);
		}
		String result = httpClient.get(param, url);
		Result info = checkResult(result);
		if(!StringUtils.isEmpty(result)&&info.isSuccess()){
			LOGGER.info("get branch success");
			return new Result(true,result,"get branch success");
		}
		return info;
	}

	@Override
	public Result getGitProjectHooks(GitLab gitLab, String private_token) {
		return null;
	}

	@Override
	public Result getGitProjectSingleHook(GitLab gitLab, String private_token, String hookId) {
		return null;
	}

	@Override
	public Result createGitProjectHook(GitLab gitLab, String private_token, String hookUrl,
			Map<String, Boolean> events) {
		return null;
	}

	@Override
	public Result deleteGitProjectHook(GitLab gitLab, String private_token) {
		return null;
	}

	@Override
	public Result gitClone(CiHost ciHost, String sourcePath, String branch, String gitAddress) {
		String command = RequestCommand.gitCloneCommand(gitAddress,sourcePath, branch);
		Result result = SSH.stdoutConnection(ciHost.getHost_ip(), ciHost.getHost_user(), ciHost.getHost_pwd(),command);
		return result;
	}

	@Override
	public Result sonarSourceScanner(CiHost ciHost, String sourcePath) {
		String command = RequestCommand.sonarAnalysisCommand(sourcePath);
		Result result = SSH.stdoutConnection(ciHost.getHost_ip(), ciHost.getHost_user(), ciHost.getHost_pwd(),command);
		return result;
	}

	@Override
	public Result mavenUnitTest(CiHost ciHost, String sourcePath) {
		String command = RequestCommand.unitTestCommand(sourcePath);
		Result result = SSH.stdoutConnection(ciHost.getHost_ip(), ciHost.getHost_user(), ciHost.getHost_pwd(),command);
		return result;
	}

	@Override
	public Result mavenSourcePackage(CiHost ciHost, String sourcePath) {
		String command = RequestCommand.mvnPackageCommand(sourcePath);
		Result result = SSH.stdoutConnection(ciHost.getHost_ip(), ciHost.getHost_user(), ciHost.getHost_pwd(),command);
		return result;
	}

	@Override
	public Result createJenkinsProject(JenkinsItem jenkinsItem){
		Result result = new Result();
		//初始化jenkins server
		try {
			jenkinsServer = new JenkinsServer(new URI(jenkinsItem.getJenkins_url()), jenkinsItem.getJenkins_user(), jenkinsItem.getJenkins_pwd());
		} catch (URISyntaxException e) {
			return new Result(false, "create jenkins server fail："+e.getMessage());
		}
		try {
			JobWithDetails jobWithDetails = jenkinsServer.getJob(jenkinsItem.getItem_name());
			if(null!=jobWithDetails){
				result.setSuccess(false);
				result.setMessage("A job already exists with the name "+jenkinsItem.getItem_name());
				return result;
			}
		} catch (IOException e) {
			return new Result(false, "jenkins get job fail："+e.getMessage());
		}
		jenkinsItem.setCommand(StringUtils.isEmpty(jenkinsItem.getCommand())?"":jenkinsItem.getCommand());
		//如果选择jenkins制作镜像，那么指定Dockerfile位置并指定镜像名称
		if(jenkinsItem.getMakeImage()==Status.JUDGE.YES.ordinal()){
			jenkinsItem.setImageName(jenkinsItem.getItem_name()+":"+Common.JENKINS_DEFAULT_IMAGE_TAG);
			jenkinsItem.setDockerfile_dir(Common.JENKINS_DOCKERFILE_DIR);
		}
		String jobXml= JenkinsJobXmls.getJobxml(jenkinsItem);
		try {
			//创建job
			jenkinsServer.createJob(jenkinsItem.getItem_name(), jobXml);
			while(jenkinsServer.getJob(jenkinsItem.getItem_name()).isInQueue()){
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					return new Result(false, "jenkins create job fail："+e.getMessage());
				}
			}
			//是否成功
			if(jenkinsServer.getJob(jenkinsItem.getItem_name()).isBuildable()){
				LOGGER.info("create a new job success");
			}else{
				LOGGER.info("create a new job fail");
				return new Result(false, "create a new job "+jenkinsItem.getItem_name()+" fail");
			}
		} catch (IOException e) {
			return new Result(false, "jenkins create job fail："+e.getMessage());
		}
		return new Result(true, jenkinsItem.getItem_name(),"create a new job "+jenkinsItem.getItem_name()+" success");
	}
	/**
	* @Title: getJobConsoleLog 
	* @Description: 日志
	* @param @param jenkinsItem
	* @param @return    设定文件 
	* @return Result    返回类型 
	* @throws
	 */
	public Result getJobConsoleLog(JenkinsItem jenkinsItem){
		//初始化jenkins server
		try {
			jenkinsServer = new JenkinsServer(new URI(jenkinsItem.getJenkins_url()), jenkinsItem.getJenkins_user(), jenkinsItem.getJenkins_pwd());
		} catch (URISyntaxException e) {
			return new Result(false, "create jenkins server fail："+e.getMessage());
		}
		try {
			JobWithDetails jobWithDetails = jenkinsServer.getJob(jenkinsItem.getItem_name());
			if(null==jobWithDetails){
				return new Result(false,"The project job ["+jenkinsItem.getItem_name()+"] is not exists");
			}
		} catch (IOException e) {
			return new Result(false, "jenkins get job fail："+e.getMessage());
		}
		try {
			//获取日志输出
			String consoleOutput = jenkinsServer.getJob(jenkinsItem.getItem_name()).getBuildByNumber(jenkinsItem.getNumber()).details().getConsoleOutputText();
			return new Result(true, consoleOutput,"console out success");
		} catch (IOException e) {
			return new Result(false, "jenkins get job fail："+e.getMessage());
		}
	}
	/**
	 * 
	* @Title: buildJob 
	* @Description: 构建应用 
	* @param @param jenkinsItem
	* @param @return    设定文件 
	* @return Result    返回类型 
	* @throws
	 */
	public Result buildJob(JenkinsItem jenkinsItem){
		Result result = new Result();
		//初始化jenkins server
		try {
			jenkinsServer = new JenkinsServer(new URI(jenkinsItem.getJenkins_url()), jenkinsItem.getJenkins_user(), jenkinsItem.getJenkins_pwd());
		} catch (URISyntaxException e) {
			return new Result(false, "create jenkins server fail："+e.getMessage());
		}
		try {
			JobWithDetails jobWithDetails = jenkinsServer.getJob(jenkinsItem.getItem_name());
			if(null==jobWithDetails){
				result.setSuccess(false);
				result.setMessage("The project job ["+jenkinsItem.getItem_name()+"] is not exists");
				return result;
			}
		} catch (IOException e) {
			return new Result(false, "jenkins get job fail："+e.getMessage());
		}
		try {
			jenkinsServer.getJob(jenkinsItem.getItem_name()).build();
			boolean isInQueue = true;
			LOGGER.info("Jenkins job "+jenkinsItem.getItem_name()+" is in quenue");
			//是否在排队等待
			long currentTime = System.currentTimeMillis();
			while(isInQueue){
				isInQueue = jenkinsServer.getJob(jenkinsItem.getItem_name()).isInQueue();
				LOGGER.info("Jenkins build job is in queue");
				if(isInQueue){
					try {
						Thread.sleep(2000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
			LOGGER.info("Jenkins waiting for "+(System.currentTimeMillis()-currentTime)/1000+"s in queue");
			boolean isbuilding = true;
			//是否构建完成
			LOGGER.info("Jenkins job "+jenkinsItem.getItem_name()+" start building");
			while(isbuilding){
				isbuilding = jenkinsServer.getJob(jenkinsItem.getItem_name()).getLastBuild().details().isBuilding();
				LOGGER.info("Jenkins job is building");
				if(isbuilding){
					try {
						Thread.sleep(2000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}	
				}
			}
			BuildResult buildResult = jenkinsServer.getJob(jenkinsItem.getItem_name()).getLastBuild().details().getResult();
			if(buildResult.equals(BuildResult.SUCCESS)){
				LOGGER.info("Jenkins building success for "+(System.currentTimeMillis()-currentTime)/1000+"s");
				//本次是第几次构建
				int number = jenkinsServer.getJob(jenkinsItem.getItem_name()).getLastBuild().getNumber();
				JSONObject jsonObject = new JSONObject();
				jsonObject.put("number",number);
				if(jenkinsItem.getMakeImage()==Status.JUDGE.YES.ordinal()){
					Result imageId = this.getImageIdByImageNameInPipeline(jenkinsItem.getItem_name()+":"+number);
					jsonObject.put("imageUuid",imageId.getData().toString());
					jsonObject.put("imageName",jenkinsItem.getItem_name());
					jsonObject.put("imageTag",number);
				}
				result = new Result(true, jsonObject, "构建完成");
			}else{
				result = new Result(false,"构建未完成,执行结果："+buildResult);
			}
		} catch (IOException e) {
			return new Result(false, "jenkins get job fail："+e.getMessage());
		}
		return result;
		
	}
	private Result checkResult(String result){
		if(StringUtils.isEmpty(result)){
			return new Result(false, "result is null");
		}
		if(result.contains("404 Project Not Found")){
			return new Result(false, "404 Project Not Found");
		}
		if(result.contains("404 Not Found")){
			return new Result(false, "404 Not Found");
		}
		if(result.contains("404 Branch Not Found")){
			return new Result(false, "404 Branch Not Found");
		}
		if(result.contains("404 Not Found")){
			return new Result(false, "404 Not Found");
		}
		return new Result(true, "");
	}
	/**
	 * 检查gitlab仓库信息
	 * @param gitLab
	 * @return
	 */
	private Result checkGitLabUrl(GitLab gitLab){
		if(StringUtils.isEmpty(gitLab.getHttp_protocol())){
			LOGGER.error("request protocol is needed");
			return new Result(false, "request protocol is needed");
		}else if(StringUtils.isEmpty(gitLab.getGitLab_url())){
			LOGGER.error("request gitlab address is needed");
			return new Result(false, "request gitlab address is needed");
		}else if(StringUtils.isEmpty(gitLab.getGitLab_port())){
			LOGGER.error("request gitlab port is needed");
			return new Result(false, "request gitlab port is needed");
		}else if(StringUtils.isEmpty(gitLab.getHttp_protocol())){
			LOGGER.error("request gitlab version is needed");
			return new Result(false, "request gitlab version is needed");
		}
		return new Result(true, "");
	}
	/**
    * @Title: getImageIdByImageName 
    * @Description: 在CI主机上获取pipeline流程的镜像id
    * @param @param imageName
    * @param @return    设定文件 
    * @return Result    返回类型 
    * @throws
     */
    @Override
    public Result getImageIdByImageNameInPipeline(String imageName){
    	String command = RequestCommand.getImageIdByImageNameCommand(imageName);
    	SSH ssh = new SSH(systemConfig.getPipelineHostIp(), 
    			systemConfig.getPipelineHostUser(), systemConfig.getPipelineHostPwd());
    	try {
			String imageIdstr = ssh.executeWithResult(command, Common.SSH_EXECUTE_LOW_OUT_TIME);
			if(!StringUtils.isEmpty(imageIdstr)){
				String imageId = imageIdstr.substring(imageIdstr.indexOf(":")+1).replace("\n", "");
				if(imageId.length()!=64){
					return new Result(false, imageIdstr);
				}
				return new Result(true,imageId,"success");
			}else{
				return new Result(false, imageIdstr);
			}
    	} catch (ConnectException e) {
    		return new Result(false, "查询镜像ID失败："+e.getMessage());
		} catch (IOException e) {
			return new Result(false, "查询镜像ID失败："+e.getMessage());
		}
    }
}
